package org.bartcr.test.unit;

import org.junit.Assert;

import java.util.Arrays;
import java.util.Collection;

public class Assertions {
    public static <T> void assertDoesNotContain(Collection<T> expected, Collection<T> actual) {
        StringBuilder correctlyNotFound = new StringBuilder();
        StringBuilder notExpectedButFound = new StringBuilder();
        for (T t : expected) {
            if (actual.contains(t)) {
                notExpectedButFound.append(notExpectedButFound.length() > 0 ? ", " : "").append(String.valueOf(t));
            } else {
                correctlyNotFound.append(correctlyNotFound.length() > 0 ? ", " : "").append(String.valueOf(t)) ;
            }
        }

        if (notExpectedButFound.length() > 0) {
            StringBuilder failMessage = new StringBuilder("\n  Collections are not equal:\n");
            if (notExpectedButFound.length() > 0) {
                failMessage.append("      Not expected but found: [").append(notExpectedButFound).append("]\n");
            }
            failMessage.append("      Correctly not found   : [").append(correctlyNotFound).append("]");
            Assert.fail(failMessage.toString());
        }

    }

    public static <T> void assertDoesNotContain(Collection<T> actual, T... elements) {
        assertDoesNotContain(Arrays.asList(elements), actual);
    }

    public static <T> void assertContains(Collection<T> expected, Collection<T> actual) {
        StringBuilder correctlyFound = new StringBuilder();
        StringBuilder expectedButNotFound = new StringBuilder();
        for (T t : expected) {
            if (actual.contains(t)) {
                correctlyFound.append(correctlyFound.length() > 0 ? ", " : "").append(String.valueOf(t)) ;
            } else {
                expectedButNotFound.append(expectedButNotFound.length() > 0 ? ", " : "").append(String.valueOf(t));
            }
        }

        if (expectedButNotFound.length() > 0) {
            StringBuilder failMessage = new StringBuilder("\n  Collections are not equal:\n");
            if (expectedButNotFound.length() > 0) {
                failMessage.append("      Expected but not found: [").append(expectedButNotFound).append("]\n");
            }
            failMessage.append("      Correctly found       : [").append(correctlyFound).append("]");
            Assert.fail(failMessage.toString());
        }
    }

    public static <T> void assertContains(Collection<T> actual, T... elements) {
        assertContains(Arrays.asList(elements), actual);
    }

    public static <T> void assertContainsExactly(Collection<T> expected, Collection<T> actual) {
        StringBuilder correctlyFound = new StringBuilder();
        StringBuilder expectedButNotFound = new StringBuilder();
        for (T t : expected) {
            if (actual.contains(t)) {
                correctlyFound.append(correctlyFound.length() > 0 ? ", " : "").append(String.valueOf(t)) ;
            } else {
                expectedButNotFound.append(expectedButNotFound.length() > 0 ? ", " : "").append(String.valueOf(t));
            }
        }

        StringBuilder foundButNotExpected = new StringBuilder();
        for (T t : actual) {
            if (!expected.contains(t)) {
                foundButNotExpected.append(foundButNotExpected.length() > 0 ? ", " : "").append(String.valueOf(t));
            }
        }

        if (expectedButNotFound.length() > 0 || foundButNotExpected.length() > 0) {
            StringBuilder failMessage = new StringBuilder("\n  Collections are not equal:\n");
            if (expectedButNotFound.length() > 0) {
                failMessage.append("      Expected but not found: [").append(expectedButNotFound).append("]\n");
            }
            if (foundButNotExpected.length() > 0) {
                failMessage.append("      Found but not expected: [").append(foundButNotExpected).append("]\n");
            }
            failMessage.append("      Correctly found       : [").append(correctlyFound).append("]");
            Assert.fail(failMessage.toString());
        }
    }

    public static <T> void assertContainsExactly(Collection<T> actual, T... elements) {
        assertContainsExactly(Arrays.asList(elements), actual);
    }
}
